#include "server.h"
#include "epoll.h"
#include "sock.h"
#include "mysqlDBConnPool.h"

#define READYEVENTNUM 5

Server::Server()
{
	sock_fd_ = 0;
	epoll_fd_ = 0;
	tp_ = nullptr;

	configfile_ = "../config.xml";
	sqlurl_.clear();
	maxmysql_num_ = 0;
	maxmysql_timeout_ = 0;
	threadnum_ = 0;
	maxthreadnum_ = 0;
}

Server::~Server()
{
	close(epoll_fd_);
	close(sock_fd_);
}

bool Server::loadServerConfig()
{
	if (!xml.initFile(configfile_.c_str()))
	{
		LOG_ERROR("parse file fail FFL[%s,%s, %d]", LOG_FFL);
		return false;
	}

	xmlNodePtr rootNode = xml.getRootNode();
	if (!rootNode)
	{
		LOG_ERROR("get root node fail FFL[%s,%s,%d]", LOG_FFL);
		return false;
	}

	xmlNodePtr mysqlNode = xml.getChildNode(rootNode, "MysqlInfo");
	if (mysqlNode)
	{
		xml.getNodePropNum(mysqlNode, "maxnum", &maxmysql_num_, sizeof(maxmysql_num_));
		xml.getNodePropNum(mysqlNode, "timeout", &maxmysql_timeout_, sizeof(maxmysql_timeout_));
#ifdef TEST_GM
		if(!maxmysql_num_)
		{
			LOG_ERROR("max mysql num is zero FFL[%s,%s,%d]", LOG_FFL);
			return false;
		}
#endif

		xmlNodePtr mysqlurlNode = xml.getChildNode(mysqlNode, "ServerUrl");
		if (mysqlurlNode)
		{
			xml.getNodePropStr(mysqlurlNode, "url", sqlurl_);
#ifdef TEST_GM 
			if(sqlurl_.empty())
			{
				LOG_ERROR("sql url is null FFL[%s,%s,%d]", LOG_FFL);
				return false;
			}
#endif
		}

	}
#ifdef TEST_GM 
	if(mysqlNode == nullptr)
	{
		LOG_ERROR("mysql node is null FFL[%s,%s,%d]", LOG_FFL);
	}
#endif 

	xmlNodePtr threadNode = xml.getChildNode(rootNode, "ThreadInfo");
#ifdef TEST_GM 
	if(threadNode == nullptr)
	{
		LOG_ERROR("thread node is null FFL[%s,%s,%d]", LOG_FFL);
	}
#endif 
	if (threadNode)
	{
		xml.getNodePropNum(threadNode, "threadnum", &threadnum_, sizeof(threadnum_));
		xml.getNodePropNum(threadNode, "maxthreadnum", &maxthreadnum_, sizeof(maxthreadnum_));
		assert(threadnum_ != 0 || maxthreadnum_ != 0);
	}


	xmlNodePtr logNode = xml.getChildNode(rootNode, "LogFile");
	if (logNode)
	{
		xml.getNodePropStr(logNode, "logstr", logstr_);
		xml.getNodePropStr(logNode, "logpath", logpath_);
#ifdef TEST_GM 
		assert(!logstr_.empty() || !logpath_.empty() || configfile_.empty());
#endif 
	}

	return true;
}

bool Server::init(size_t port)
{
	if (!loadServerConfig())
	{
		LOG_ERROR("server init load config fail");
		return false;
	}

	COM::logger = new qLogger(logstr_);
	if (!COM::logger)
	{
		LOG_ERROR("new log fail FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	COM::logger->addLocalFileLog(logpath_);

	LOG_INFO("HELLO");

	epoll_fd_ = EpollOpt::CreateEpoll();
	if (epoll_fd_ == -1)
	{
		LOG_ERROR("create epoll err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	sock_fd_ = SockOpt::Socket();
	if (sock_fd_ == -1)
	{
		LOG_ERROR("socket err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	if (-1 == SockOpt::SetSockOpt(sock_fd_))
	{
		LOG_ERROR("set sock opt err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	if (-1 == SockOpt::Bind(sock_fd_, port))
	{
		LOG_ERROR("bind err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}


	if (-1 == SockOpt::Listen(sock_fd_))
	{
		LOG_ERROR("ilsten err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	tp_ = ThreadPool::getInstance();
	tp_->setMaxThreadNum(maxthreadnum_);
	if (!tp_->init(threadnum_))
	{
		LOG_ERROR("server init thread pool init fail");
		return false;
	}

	MysqlConnPool* mpool = MysqlConnPool::getInstance();
	if (mpool)
	{
		mpool->setMaxNum(maxmysql_num_);
		mpool->setTimeOut(maxmysql_timeout_);
		if (mpool->init(sqlurl_.c_str()) == false)
		{
			LOG_ERROR("mysql pool init fail");
			return false;
		}
	}
	else
	{
		LOG_ERROR("get mysql pool fail");
		return false;
	}

	//加到epoll中
	struct Task* tk = new Task(epoll_fd_, sock_fd_, (void*)handleSock);
	if (-1 == EpollOpt::AddEpoll(epoll_fd_, sock_fd_, EPOLLIN, (void*)tk))
	{
		LOG_ERROR("add epoll err FFL[%s, %s, %d]", LOG_FFL);
		return false;
	}

	//daemon(1, 1);
	LOG_INFO("SERVER INIT SUCC");
	return true;
}

void Server::handleEvent(void* ptr)
{
	//处理请求，构建响应，发送响应
	if (!ptr)
	{
		LOG_ERROR("FFL[%s, %s, %d] ptr is null", LOG_FFL);
		return;
	}

	Task* tk = (Task*)ptr;
#define RECVBUFLEN 4096
	char buf[RECVBUFLEN] = { 0 };
	int num = SockOpt::Recv(buf, RECVBUFLEN - 1, tk->fd_);
	if (num <= 0)
	{
		LOG_ERROR("recv fail sock:%d, num:%d", tk->fd_, num);
		//接收数据失败
		//当前sockfd下没有任务的话，将sockfd从epoll中删除
		//if (ThreadPool::getInstance()->getSockTaskNum(tk->fd_) <= 0)
		//{
		//	EpollOpt::DelEpoll(tk->epollfd_, tk->fd_);
		//	close(tk->fd_);
		//}
		//delete tk;
		tk->state_ = 4;//需要被删除
		return;
	}

	//收到数据buff，处理请求
	HttpEndPoint* endpoint = new HttpEndPoint(tk->fd_);
	endpoint->parseHttpMsg(buf, num);
	
	//构建响应，发送响应
	endpoint->makeResponse();
	endpoint->sendResponse();
	delete endpoint;

	ThreadPool::getInstance()->subSockTaskNum(tk->fd_);
	//当前sockfd下没有任务的话，将sockfd从epoll中删除
	//if (ThreadPool::getInstance()->getSockTaskNum(tk->fd_) <= 0)
	//{
	//	EpollOpt::DelEpoll(tk->epollfd_, tk->fd_);
	//	Logger::info("FFL[%s, %s, %d] close sock:%d", LOG_FFL, tk->fd_);
	//}
	tk->state_ = 3;//需要被删除
}


void Server::handleInEvent(void* ptr)
{
	if (!ptr)
	{
		LOG_ERROR("FFL[%s, %s, %d] ptr is nullptr");
		return;
	}
	Task* tk = (Task*)ptr;

	//注意 客户端关闭 会给服务器发送消息，但是数据长度为0，需要删除等待事件
	char buf[40960];
	bzero(buf, 40960);
	//得到的是处理完报头的消息
	std::cout << "wait :" << tk->fd_ << std::endl;
	//int num = SockOpt::RecvCmd(buf, 4096, sockfd, false);
	//tk->state_ = 1;
	int num = SockOpt::Recv(buf, 40960 - 1, tk->fd_);
	if (num < 0)
	{
		LOG_ERROR("recv err FFL[%s, %s, %d]", LOG_FFL);
		if (EpollOpt::DelEpoll(tk->epollfd_, tk->fd_) == 0)
		{
			delete tk;
		}
	}
	else if (num == 0)
	{
		//客户端关闭,关闭对应客户端socket
		LOG_INFO("delete tk %u, %u", tk->epollfd_, tk->fd_);
		//close(tk->fd_);
		if (EpollOpt::DelEpoll(tk->epollfd_, tk->fd_) == 0)
		{
			Logger::info("$$$$$client close fd:%d", tk->fd_);
			delete tk;
		}
	}
	else
	{
		HttpMessageQueue* http_mess_que_ = HttpMessageQueue::getInstance();
		HttpEndPoint* endpoint = new HttpEndPoint(tk->fd_);
		endpoint->parseHttpMsg(buf, num);
		http_mess_que_->addEndPoint(tk->fd_, endpoint);

		//处理消息
		//parseUserCmd(buf, num);
		//没有消息放回的看下是返回的什么，就是没返回
		tk->event_ = (void*)handleOutEvent;
		EpollOpt::ModEpoll(tk->epollfd_, tk->fd_, EPOLLOUT, tk);
		Logger::info("FFL[%s, %s, %d] epollfd:%u, fd:%u", LOG_FFL, tk->epollfd_, tk->fd_);

	}
}

void Server::handleInETEvent(void* ptr)
{
	if (!ptr)
	{
		LOG_ERROR("FFL[%s, %s, %d] ptr is nullptr");
		return;
	}
	Task* tk = (Task*)ptr;

	char buf[40960] = { 0 };
	bzero(buf, 40960);
	//tk->state_ = 1;
	ssize_t read_offset = 0;
	ssize_t num = 0;
	do
	{
		read_offset = SockOpt::Recv(buf + read_offset, 40960 - read_offset - 1, tk->fd_);
		if (read_offset < 0)
		{
			if (errno == EAGAIN || errno == EWOULDBLOCK)
			{
				break;
			}
			else
			{
				Logger::error("连接出现错误， 从epoll中移除，fd:%d", tk->fd_);
				EpollOpt::DelEpoll(tk->epollfd_, tk->fd_);
				delete tk;
				break;
			}
		}
		if (read_offset > 0)
		{
			num += read_offset;
		}
		Logger::info("EpollEt recv fd:%d, read_offset:%d", tk->fd_, read_offset);

	} while (read_offset > 0);

	buf[num] = '\0';
	if (num <= 0)
	{
		Logger::info("buff is null fd:%u, num:%u, len:%u", tk->fd_, num, strlen(buf));
		return;
	}

	HttpMessageQueue* http_mess_que_ = HttpMessageQueue::getInstance();
	HttpEndPoint* endpoint = new HttpEndPoint(tk->fd_);
	endpoint->parseHttpMsg(buf, num);
	http_mess_que_->addEndPoint(tk->fd_, endpoint);

	tk->event_ = (void*)handleOutEvent;
	EpollOpt::ModEpoll(tk->epollfd_, tk->fd_, EPOLLOUT, tk);
	Logger::info("FFL[%s, %s, %d] epollfd:%u, fd:%u", LOG_FFL, tk->epollfd_, tk->fd_);
}

void Server::handleOutEvent(void* ptr)
{
	if (!ptr)
		return;

	//短链接，发送完后关闭连接
	Task* tk = (Task*)ptr;

	if (!tk->epollfd_ || !tk->fd_ || !tk->event_)
	{
		LOG_ERROR("task deleted FFL[%s, %s, %d]");
		return;
	}
	HttpMessageQueue* http_mess_que_ = HttpMessageQueue::getInstance();
	HttpEndPoint* endpoint = http_mess_que_->getEndPoint(tk->fd_);
	if (!endpoint)
	{
		if (!http_mess_que_->getSockEndPointNum(tk->fd_))
		{
			LOG_ERROR("FFL[%s, %s, %d] not found req fd:%u", LOG_FFL, tk->fd_);
			if (EpollOpt::DelEpoll(tk->epollfd_, tk->fd_) == 0)
			{
				Logger::info("$$$$$not found endpoint fd:%d", tk->fd_);
				delete tk;
			}
		}
		return;
	}

	//tk->state_ = 2;
	endpoint->makeResponse();
	endpoint->sendResponse();

	delete endpoint;
	if (!http_mess_que_->getSockEndPointNum(tk->fd_))
	{
		int ret = EpollOpt::DelEpoll(tk->epollfd_, tk->fd_);
		if (ret)
		{
			Logger::info("FFL[%s,%s, %d],epoll del fail, epollfd:%u, sockfd:%u, ret:%u", LOG_FFL, tk->epollfd_, tk->fd_, ret);
			return;
		}
		Logger::info("$$$$$sock num is zero fd:%d", tk->fd_);
		delete tk;
		return;
	}
	Logger::info("!!!!!!!!!!!!FFL[%s,%s, %d], epollfd:%u, sockfd:%u", LOG_FFL, tk->epollfd_, tk->fd_);
}

void Server::handleSock(void* ptr)
{
	if (!ptr)
	{
		LOG_ERROR("FFL[%s, %s, %d] ptr is nullptr");
		return;
	}

	Task* tk = (Task*)ptr;

	struct sockaddr_in peer;
	int peer_len = 0;
	int sock = SockOpt::Accept(tk->fd_, &peer, &peer_len);
	if (sock < 0)
	{
		return;
	}
	std::cout << "get a link " << sock << ":" << tk->fd_ << std::endl;

	//ET工作模式，设置为非阻塞
	//int flag = fcntl(sock, F_GETFL, 0);
	//fcntl(sock, F_SETFL, flag | O_NONBLOCK);

	struct Task* newtk = new Task(tk->epollfd_, sock, (void*)handleEvent);
	//newtk->event_ = (void*)handleInEvent;
	if (-1 == EpollOpt::AddEpoll(tk->epollfd_, sock, EPOLLIN, (void*)newtk))
	{
		LOG_ERROR("addepoll fail FFL[%s, %s, %d]", LOG_FFL);
		delete newtk;
	}
}

void Server::handleEpoll(struct epoll_event* evts, int size)
{
	for (int i = 0; i < size && i < READYEVENTNUM; ++i)
	{
		Task* tk = (Task*)evts[i].data.ptr;
		if (!tk || !tk->epollfd_ || !tk->fd_)
			continue;

		if (evts[i].events &  EPOLLIN)
		{
			if (tk->fd_ == sock_fd_)
			{
				HANDLE func = (HANDLE)tk->event_;
				func(tk);
			}
			else
			{
				//已经put到任务队列了
				if (tk->state_ != 0)
				{
					//sleep(1);
					Logger::info("FFL[%s, %s, %d] task is running sock:%d state:%d", LOG_FFL, tk->fd_, tk->state_);
					continue;
				}
				Logger::info("EPOLLIN puttask fd:%u, epollfd:%u, theadid:%u", tk->fd_, epoll_fd_, pthread_self());
				tp_->putTask(tk);
				//usleep(100);
			}

		}
		else if (evts[i].events & EPOLLOUT)
		{
			//已經put到任務隊列了
			if (tk->state_ == 1)
			{
				//sleep(1);
				Logger::info("FFL[%s, %s, %d] task is running sock:%d state:%d", LOG_FFL, tk->fd_, tk->state_);
				continue;
			}
			Logger::info("EPOLLOUT puttask fd:%u, epollfd:%u, threadid:%u", tk->fd_, tk->epollfd_, pthread_self());
			tp_->putTask(tk);
		}
		else
		{
			Logger::info("FFL[%s, %s, %d] othrer event", LOG_FFL);
		}
	}
}

void Server::start()
{
	int timeout = -1;
	while (true)
	{
		struct epoll_event evts[READYEVENTNUM];
		int n = EpollOpt::WaitEpoll(epoll_fd_, evts, READYEVENTNUM, timeout);
		if (n == 0)
		{
			LOG_ERROR("wait epoll timeout FFL[%s, %s, %d]", LOG_FFL);
		}
		else if (n < 0)
		{
			LOG_ERROR("wait epoll fail FFL[%s, %s, %d]", LOG_FFL);
			return;
		}
		else
		{
			handleEpoll(evts, n);
			//usleep(100);
		}

		//检查任务是否有state为3的

	}
}
